/*******************************************************************************
 *
 * Copyright (c) 2008-2011 ayound@gmail.com
 * This program and the accompanying materials
 * are made available under the terms of the GNU GENERAL PUBLIC LICENSE
 * which accompanies this distribution, and is available at
 * http://dev.perl.org/licenses/gpl1.html
 * All rights reserved.
 *
 * Created on 2009-11-10
 *******************************************************************************/


package org.ayound.skin.editor.core;


import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.awt.image.DataBuffer;
import java.awt.image.FilteredImageSource;
import java.awt.image.MemoryImageSource;
import java.awt.image.PixelGrabber;
import java.awt.image.RGBImageFilter;

import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.SwingConstants;
import javax.swing.plaf.ColorUIResource;


public final class ImageUtils implements SwingConstants {

	/**
	 * Description of the Field
	 */
	public final static Component producer = new java.awt.Component() {};

	/**
	 * Description of the Field
	 */
	public final static int PAINT_NORMAL = 0;
	/**
	 * Description of the Field
	 */
	public final static int PAINT_STRETCH = 1;
	/**
	 * Description of the Field
	 */
	public final static int PAINT_CENTERED = 3;
	/**
	 * Description of the Field
	 */
	public final static int PAINT_NONE = 5;

	/**
	 * Description of the Field
	 */
	public final static int TRANSPARENT_RED = 255;
	/**
	 * Description of the Field
	 */
	public final static int TRANSPARENT_GREEN = 0;
	/**
	 * Description of the Field
	 */
	public final static int TRANSPARENT_BLUE = 255;
	/**
	 * Description of the Field
	 */
	public final static int TRANSPARENT_TO_REMOVE = new Color(255, 0, 255).getRGB();
	/**
	 * Description of the Field
	 */
	public final static int TRANSPARENT_PIXEL = new Color(255, 0, 0, 0).getRGB();

	/**
	 * Gets the DisabledIcon attribute of the ImageUtils class
	 *
	 * @param anIcon  Description of Parameter
	 * @return        The DisabledIcon value
	 */
	public static ImageIcon getDisabledIcon(ImageIcon anIcon) {
		return getDisabledIcon(anIcon.getImage());
	}

	/**
	 * Gets the DisabledIcon attribute of the ImageUtils class
	 *
	 * @param anImage  Description of Parameter
	 * @return         The DisabledIcon value
	 */
	public static ImageIcon getDisabledIcon(Image anImage) {
		return new ImageIcon(getDisabledImage(anImage));
	}

	/**
	 * Gets the DisabledImage attribute of the ImageUtils class
	 *
	 * @param anImage  Description of Parameter
	 * @return         The DisabledImage value
	 */
	public static Image getDisabledImage(Image anImage) {
		if (anImage == null) {
			return null;
		} else {
			return filterImage(new javax.swing.GrayFilter(true, 75), anImage);
		}
	}

	/**
	 * Description of the Method
	 *
	 * @param filter  Description of Parameter
	 * @param image   Description of Parameter
	 * @return        Description of the Returned Value
	 */
	public static Image filterImage(RGBImageFilter filter, Image image) {
		return producer.createImage(new FilteredImageSource(image.getSource(), filter));
	}

	/**
	 * Description of the Method
	 *
	 * @param anImage  Description of Parameter
	 * @return         Description of the Returned Value
	 */
	public static Image rotateImage(Image anImage) {
		int w = anImage.getWidth(null);
		int h = anImage.getHeight(null);
		int[] pixels = new int[w * h];

		PixelGrabber pixel = new PixelGrabber(anImage, 0, 0, w, h, pixels, 0, w);
		try {
			pixel.grabPixels();
		} catch (Exception e) {
			//	    e.printStackTrace();
		}

		int[] rot = new int[h * w];
		int pos = 0;

		for (int i = w; i > 0; i--) {
			for (int j = 0; j < h; j++) {
				rot[pos] = pixels[i + (w * j) - 1];
				pos++;
			}
		}

		return convertBytesToImage(producer, rot, h, w);
	}

	/**
	 * Description of the Method
	 *
	 * @param anImage  Description of Parameter
	 * @param angle    Description of Parameter
	 * @return         Description of the Returned Value
	 */
	public static Image rotateImage(Image anImage, double angle) {
		int width = anImage.getWidth(null);
		int height = anImage.getHeight(null);
		int[] pixels = new int[width * height];

		PixelGrabber pixel = new PixelGrabber(anImage, 0, 0, width, height, pixels, 0, width);
		try {
			pixel.grabPixels();
		} catch (Exception e) {
			//    e.printStackTrace();
		}

		int[] pixels2 = new int[width * height];

		int i = 0;
		double radians = -angle / (180 / Math.PI);
		double cos = Math.cos(radians);
		double sin = Math.sin(radians);
		int centerX = width >> 1;
		int centerY = height >> 1;
		for (int oldY = -centerY; oldY < centerY; oldY++) {
			for (int oldX = -centerX; oldX < centerX; oldX++) {
				int newX = centerX + (int) ((oldX * cos) - (oldY * sin));
				int newY = centerY + (int) ((oldX * sin) + (oldY * cos));
				if (newX > 0 && newX < width && newY > 0 && newY < height) {
					pixels2[i++] = pixels[(width * newY) + newX];
				} else {
					pixels2[i++] = pixels[0];
				}
			}
		}
		return producer.createImage(new MemoryImageSource(width, height, pixels2, 0, width));
	}

	/**
	 * Description of the Method
	 *
	 * @param c       Description of Parameter
	 * @param pixels  Description of Parameter
	 * @param w       Description of Parameter
	 * @param h       Description of Parameter
	 * @return        Description of the Returned Value
	 */
	public static Image convertBytesToImage(Component c, int[] pixels, int w, int h) {
		return c.createImage(new MemoryImageSource(w, h, pixels, 0, w));
	}



	/**
	 * Description of the Method
	 *
	 * @param image  Description of Parameter
	 * @return       Description of the Returned Value
	 */
	public static Image transparent(Image image) {
		return toBufferedImage(image);
	}

	/**
	 * Description of the Method
	 *
	 * @param image   Description of Parameter
	 * @param x       Description of Parameter
	 * @param y       Description of Parameter
	 * @param width   Description of Parameter
	 * @param height  Description of Parameter
	 * @return        Description of the Returned Value
	 */
	public static Image grab(Image image, int x, int y, int width, int height) {
		if (width * height <= 0) {
			return null;
		}

		if (image instanceof BufferedImage) {
			return ((BufferedImage)image).getSubimage(x, y, width, height);
		}

		int[] pixels = new int[width * height];
		PixelGrabber grabber = new PixelGrabber(image, x, y, width, height, pixels, 0, width);
		try {
			grabber.grabPixels();
		} catch (Exception e) {
			e.printStackTrace();
		}

		int pixel, red, green, blue;

		for (int j = 0; j < height; j++) {
			for (int i = 0; i < width; i++) {
				pixel = pixels[j * width + i];
				red = (pixel >> 16) & 0xff;
				green = (pixel >> 8) & 0xff;
				blue = (pixel) & 0xff;
				if ((red == TRANSPARENT_RED) && (green == TRANSPARENT_GREEN) && (blue == TRANSPARENT_BLUE)) {
					pixels[j * width + i] = TRANSPARENT_PIXEL;
				}
			}
		}

		Image newImage = producer.createImage(new MemoryImageSource(width, height, pixels, 0, width));
		return toBufferedImage(newImage);
	}


	/**
	 * Description of the Method
	 *
	 * @param image  Description of Parameter
	 * @return       Description of the Returned Value
	 */
	public static BufferedImage toBufferedImage(Image image) {
		if (image == null) {
			return null;
		}

    if (image instanceof BufferedImage) {
      return (BufferedImage)image;
    }

		// This code ensures that all the pixels in
		// the image are loaded.
		image = new ImageIcon(image).getImage();

		// Create the buffered image.
		BufferedImage bufferedImage = new BufferedImage(image.getWidth(null), image.getHeight(null), BufferedImage.TYPE_INT_ARGB);

		// Copy image to buffered image.
		Graphics2D g = bufferedImage.createGraphics();

		// paint the image.
		g.drawImage(image, 0, 0, null);
		g.dispose();

		// Get the DataBuffer from your bufferedImage like
		DataBuffer db = bufferedImage.getRaster().getDataBuffer();
		// then you can just iterate through and convert your chosencolor to a transparent color
		for (int i = 0, c = db.getSize(); i < c; i++) {
			if (db.getElem(i) == TRANSPARENT_TO_REMOVE) {
				// set to transparent
				db.setElem(i, TRANSPARENT_PIXEL);
			}
		}

		return bufferedImage;
	}

}
